﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Web;

namespace CommonEngine.Helper
{
    /// <summary>
    /// 编解码器
    /// </summary>
    public sealed class CodecHelper
    {
        #region--Aes--

        /*密码学中的高级加密标准（Advanced Encryption Standard，AES），又称Rijndael加密法，是美国联邦政府采用的一种区块加密标准。*/

        public static string EncryptStringToBytes_Aes(string plainText, string sKey, string sIV)
        {
            var Key = Convert.FromBase64String(sKey);
            var IV = Convert.FromBase64String(sIV);

            // Check arguments.
            if (plainText == null || plainText.Length <= 0)
                throw new ArgumentNullException("plainText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("IV");
            byte[] encrypted;
            // Create an AesCryptoServiceProvider object
            // with the specified key and IV.
            using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
            {
                aesAlg.Key = Key;
                aesAlg.IV = IV;

                // Create a decrytor to perform the stream transform.
                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

                // Create the streams used for encryption.
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {

                            //Write all data to the stream.
                            swEncrypt.Write(plainText);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }


            // Return the encrypted bytes from the memory stream.
            return Convert.ToBase64String(encrypted);

        }

        public static string DecryptStringFromBytes_Aes(string sCipherText, string sKey, string sIV)
        {
            var cipherText = Convert.FromBase64String(sCipherText);

            var Key = Convert.FromBase64String(sKey);
            var IV = Convert.FromBase64String(sIV);

            // Check arguments.
            if (cipherText == null || cipherText.Length <= 0)
                throw new ArgumentNullException("cipherText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("IV");

            // Declare the string used to hold
            // the decrypted text.
            string plaintext = null;

            // Create an AesCryptoServiceProvider object
            // with the specified key and IV.
            using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
            {
                aesAlg.Key = Key;
                aesAlg.IV = IV;

                // Create a decrytor to perform the stream transform.
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

                // Create the streams used for decryption.
                using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {

                            // Read the decrypted bytes from the decrypting stream
                            // and place them in a string.
                            plaintext = srDecrypt.ReadToEnd();
                        }
                    }
                }
            }

            return plaintext;
        }

        #endregion

        #region---DES---Java、PHP、C#通用---

        static string key = "LHY";

        #region DES加密

        public static string DES_Encrypt(string Text)
        {
            return DES_Encrypt(Text, key);
        }

        public static string DES_Encrypt(string Text, string sKey)
        {
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();

            byte[] inputByteArray;
            inputByteArray = Encoding.Default.GetBytes(Text);
            des.Key = ASCIIEncoding.ASCII.GetBytes(Md5Hash(sKey).Substring(0, 8));
            des.IV = ASCIIEncoding.ASCII.GetBytes(Md5Hash(sKey).Substring(0, 8));
            System.IO.MemoryStream ms = new System.IO.MemoryStream();

            CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);

            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();

            StringBuilder ret = new StringBuilder();

            foreach (byte b in ms.ToArray())
            {
                ret.AppendFormat("{0:X2}", b);
            }

            return ret.ToString();
        }

        #endregion

        #region DES解密

        public static string DES_Decrypt(string Text)
        {
            return DES_Decrypt(Text, key);
        }

        public static string DES_Decrypt(string Text, string sKey)
        {
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();

            int len;
            len = Text.Length / 2;
            byte[] inputByteArray = new byte[len];
            int x, i;

            for (x = 0; x < len; x++)
            {
                i = Convert.ToInt32(Text.Substring(x * 2, 2), 16);
                inputByteArray[x] = (byte)i;
            }

            des.Key = ASCIIEncoding.ASCII.GetBytes(Md5Hash(sKey).Substring(0, 8));
            des.IV = ASCIIEncoding.ASCII.GetBytes(Md5Hash(sKey).Substring(0, 8));
            System.IO.MemoryStream ms = new System.IO.MemoryStream();

            CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);

            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();

            return Encoding.Default.GetString(ms.ToArray());
        }

        #endregion

        #endregion

        #region---DES---实现2

        /// <summary>
        /// DES加密
        /// </summary>
        public static string EncryptString(string encryptString)
        {
            if (string.IsNullOrEmpty(encryptString))
            {
                throw new ArgumentNullException("encryptString", "不能为空");
            }

            byte[] keyBytes = Encoding.UTF8.GetBytes(key);
            byte[] keyIV = keyBytes;
            byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
            byte[] resultByteArray = EncryptBytes(inputByteArray, keyBytes, keyIV);
            return Convert.ToBase64String(resultByteArray);
        }
        private static byte[] EncryptBytes(byte[] sourceBytes, byte[] keyBytes, byte[] keyIV)
        {
            if (sourceBytes == null || keyBytes == null || keyIV == null)
            {
                throw new ArgumentNullException("sourceBytes和keyBytes", "不能为空。");
            }
            else
            {
                keyBytes = CheckByteArrayLength(keyBytes);
                keyIV = CheckByteArrayLength(keyIV);
                DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
                MemoryStream mStream = new MemoryStream();
                CryptoStream cStream = new CryptoStream(mStream, provider.CreateEncryptor(keyBytes, keyIV), CryptoStreamMode.Write);
                cStream.Write(sourceBytes, 0, sourceBytes.Length);
                cStream.FlushFinalBlock();
                byte[] buffer = mStream.ToArray();
                mStream.Close();
                cStream.Close();
                return buffer;
            }
        }

        /// <summary>
        /// DES解密
        /// </summary>
        public static string DecryptString(string decryptString)
        {
            if (string.IsNullOrEmpty(decryptString))
            {
                throw new ArgumentNullException("decryptString", "不能为空");
            }
            byte[] keyBytes = Encoding.UTF8.GetBytes(key);
            byte[] keyIV = keyBytes;
            byte[] inputByteArray = Convert.FromBase64String(decryptString);
            byte[] resultByteArray = DecryptBytes(inputByteArray, keyBytes, keyIV);
            return Encoding.UTF8.GetString(resultByteArray);
        }
        private static byte[] DecryptBytes(byte[] sourceBytes, byte[] keyBytes, byte[] keyIV)
        {
            if (sourceBytes == null || keyBytes == null || keyIV == null)
            {
                throw new ArgumentNullException("soureBytes和keyBytes及keyIV", "不能为空。");
            }
            else
            {
                keyBytes = CheckByteArrayLength(keyBytes);
                keyIV = CheckByteArrayLength(keyIV);
                DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
                MemoryStream mStream = new MemoryStream();
                CryptoStream cStream = new CryptoStream(mStream, provider.CreateDecryptor(keyBytes, keyIV), CryptoStreamMode.Write);
                cStream.Write(sourceBytes, 0, sourceBytes.Length);
                cStream.FlushFinalBlock();
                byte[] buffer = mStream.ToArray();
                mStream.Close();
                cStream.Close();
                return buffer;
            }
        }
        /// <summary>
        /// 密钥长度，如果不是8的倍数或长度大于64则截取前8个元素
        /// </summary>
        private static byte[] CheckByteArrayLength(byte[] byteArray)
        {
            byte[] resultBytes = new byte[8];
            if (byteArray.Length < 8)
            {
                return Encoding.UTF8.GetBytes("12345678");
            }
            else if (byteArray.Length % 8 != 0 || byteArray.Length > 64)
            {
                Array.Copy(byteArray, 0, resultBytes, 0, 8);
                return resultBytes;
            }
            else
            {
                return byteArray;
            }
        }

        #endregion

        #region---字符串64编解码---

        public static string Encode64(string Text)
        {
            var V = ConvertStringEncode(Text);
            return ConvertStringToBase64(V);
        }

        public static string Decode64(string Text)
        {
            string V = ConvertBase64ToString(Text);
            return ConvertStringDecode(V);
        }

        /// <summary>
        /// 双编码
        /// </summary>
        public static string ConvertStringEncode(string inputString)
        {
            string outputString = string.Empty;
            outputString = HttpUtility.UrlEncode(inputString);
            outputString = Uri.EscapeDataString(outputString);

            return outputString;
        }

        /// <summary>
        /// 双解码
        /// </summary>
        public static string ConvertStringDecode(string inputString)
        {
            string outputString = string.Empty;

            outputString = HttpUtility.UrlDecode(inputString);
            outputString = Uri.UnescapeDataString(outputString);

            return outputString;
        }

        /// <summary>
        /// 转64字符串
        /// </summary>
        public static string ConvertStringToBase64(string str)
        {
            if (string.IsNullOrEmpty(str))
                return string.Empty;

            try
            {
                byte[] byteArray = Encoding.UTF8.GetBytes(str);
                string base64 = Convert.ToBase64String(byteArray);
                return base64;
            }
            catch
            {
                return str;
            }
        }

        /// <summary>
        /// 64转正常字符串
        /// </summary>
        public static string ConvertBase64ToString(string base64Str)
        {
            if (string.IsNullOrEmpty(base64Str))
                return string.Empty;

            try
            {
                byte[] bytes = Convert.FromBase64String(base64Str);
                string str = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
                return str;
            }
            catch
            {
                return base64Str;
            }
        }

        #endregion

        #region ----STS----加密和解密算法----为加密狗准备

        private static SymmetricAlgorithm mobjCryptoService = new RijndaelManaged();
        /// <summary>     
        /// 获得密钥     
        /// </summary>     
        /// <returns>密钥</returns>     
        private static byte[] GetLegalKey()
        {
            string sTemp = "Luo";
            mobjCryptoService.GenerateKey();
            byte[] bytTemp = mobjCryptoService.Key;
            int KeyLength = bytTemp.Length;
            if (sTemp.Length > KeyLength)
                sTemp = sTemp.Substring(0, KeyLength);
            else if (sTemp.Length < KeyLength)
                sTemp = sTemp.PadRight(KeyLength, ' ');
            return ASCIIEncoding.ASCII.GetBytes(sTemp);
        }
        /// <summary>     
        /// 获得初始向量IV     
        /// </summary>     
        /// <returns>初试向量IV</returns>     
        private static byte[] GetLegalIV()
        {
            string sTemp = "Hongye";
            mobjCryptoService.GenerateIV();
            byte[] bytTemp = mobjCryptoService.IV;
            int IVLength = bytTemp.Length;
            if (sTemp.Length > IVLength)
                sTemp = sTemp.Substring(0, IVLength);
            else if (sTemp.Length < IVLength)
                sTemp = sTemp.PadRight(IVLength, ' ');
            return ASCIIEncoding.ASCII.GetBytes(sTemp);
        }
        /// <summary>     
        /// 加密方法     
        /// </summary>     
        /// <param name="Source">待加密的串</param>
        /// <returns>经过加密的串</returns>     
        public static string Encrypto(string Source)
        {
            byte[] bytIn = UTF8Encoding.UTF8.GetBytes(Source);
            MemoryStream ms = new MemoryStream();
            mobjCryptoService.Key = GetLegalKey();
            mobjCryptoService.IV = GetLegalIV();
            ICryptoTransform encrypto = mobjCryptoService.CreateEncryptor();
            CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Write);
            cs.Write(bytIn, 0, bytIn.Length);
            cs.FlushFinalBlock();
            ms.Close();
            byte[] bytOut = ms.ToArray();
            return Convert.ToBase64String(bytOut);
        }
        /// <summary>     
        /// 解密方法     
        /// </summary>     
        /// <param name="Source">待解密的串</param>
        /// <returns>经过解密的串</returns>     
        public static string Decrypto(string Source)
        {
            byte[] bytIn = Convert.FromBase64String(Source);
            MemoryStream ms = new MemoryStream(bytIn, 0, bytIn.Length);
            mobjCryptoService.Key = GetLegalKey();
            mobjCryptoService.IV = GetLegalIV();
            ICryptoTransform encrypto = mobjCryptoService.CreateDecryptor();
            CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Read);
            StreamReader sr = new StreamReader(cs);
            return sr.ReadToEnd();
        }

        #endregion

        public static string SHA1Hash(string input)
        {
            System.Security.Cryptography.SHA1 algorithm = System.Security.Cryptography.SHA1.Create();
            byte[] data = algorithm.ComputeHash(System.Text.Encoding.Default.GetBytes(input));
            System.Text.StringBuilder sBuilder = new System.Text.StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }
            return sBuilder.ToString().ToUpper();
        }

        public static string Md5Hash(string input)
        {
            System.Security.Cryptography.MD5CryptoServiceProvider md5Hasher = new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] data = md5Hasher.ComputeHash(System.Text.Encoding.Default.GetBytes(input));
            System.Text.StringBuilder sBuilder = new System.Text.StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }
            return sBuilder.ToString().ToUpper();
        }

        /// <summary>
        /// 参考：--https://blog.csdn.net/a19860903/article/details/53731235
        /// 各自语言通用的加密算法（不可逆加密），通常用于生成Token
        /// </summary>
        public static string HmacSHA256(string message, string secret)
        {
            secret = secret ?? "";
            var encoding = new System.Text.ASCIIEncoding();
            using (var hmacsha256 = new System.Security.Cryptography.HMACSHA256(encoding.GetBytes(secret)))
            {
                byte[] hashmessage = hmacsha256.ComputeHash(encoding.GetBytes(message));
                return Convert.ToBase64String(hashmessage);
            }
        }
    }
}
